/**
 * 键盘小工具
 */
#ifndef __CLION_CPPTEST_KEYBOARDUTILS_H__
#define __CLION_CPPTEST_KEYBOARDUTILS_H__
#include <stdio.h>
#include <conio.h>

enum KeyBoard_Type {
    /**
     * ASCII码, 键盘能收到的最小正常ASCII值: backspace: 删除
     * 参考: https://baike.baidu.com/link?url=gj9RJbDPsEx_uu-UE6Ltr9szlNXyo55SoXo125M1NIp0ylrfNoz3lXrrd67cX-U9d1X0HhwjzQIW4HRHhZ5vcq
     */
    Ascii = 8,
    UnAscii = 128,   //非ASCII

    /**
     * F1~F10   : 有2次输入组合, 第1次=0
     */
    F1_F10 = 59,     //F1_F10        : 第2次: 59~68
    Fn_F1_F10 = 84,  //Shift + F1_F10: 功能键, 第2次: 84~93

    /**
     * 另外功能键的输入组合, 第1次=224
     */
    Home = 71,       //Home           : 第2次: 71
    PageUp = 73,     //page up        : 第2次: 73
    End = 79,        //End            : 第2次: 79
    PageDown = 81,   //page down      : 第2次: 81
    Delete = 83,     //Delete         : 第2次=83
    F11_F12 = 133,   //F11,F12        : 第2次: 133~134
    Fn_F11_F12 = 135,//Shift + F11,F12: 功能键, 第2次: 135~136
    Arrow = 224      //箭头            : 第2次: ↑72, ←75, →77, ↓80
};

struct Keyboard_Key {
    //按键是按下状态, 还是弹起状态
    BOOLEAN isPressed;
    /**
     * 如果是按下状态
     * 1.键盘类型
     */
    enum KeyBoard_Type keyBoardType;
    //2.按下的字母
    int ch;
};

/**
 * 实现非阻塞式键盘监听, 查看按键缓冲区中是否有字符，有返回true，没有返回false <br />
 * 头文件: include <conio.h>
 * @return 0无, 否则有
 */
BOOLEAN kb_hint() {
    return kbhit();
}


//组合键, 以0开头
#define combination_key_0  0
//组合键, 以224开头
#define combination_key_224  224

//输入组合, 以0开头
static int isStart0 = 0;
//输入组合, 以224开头
static int isStart224 = 0;
static int ch;
struct Keyboard_Key keyboardKey = {FALSE, UnAscii, 0};

/**
 * 添加键盘监听, 不能监听的键: prt_sc, caps_lock, shift, ctrl, fn, win, alt, num_lock <br />
 * 调用示例: <br />
 *   &emsp;  while (1) { <br />
 *   &emsp;&emsp;      struct Keyboard_Key key = getKeyInput(0); <br />
 *   &emsp;&emsp;      if (key.isPressed) {...}; <br />
 *   &emsp;&emsp;      ... <br />
 *   &emsp;  } <br />
 * @param isPrintLog 是否打印日志
 */
struct Keyboard_Key getKeyInput(int isPrintLog) {
    //∵有些是组合键, 要检测2次, 所以用while, 而不用if
    while (kb_hint()) {
        ch = getch();
        /**
         * 1.先判断是否输入的是组合键
         */
        if (isStart0) {
            if (ch >= F1_F10 && ch <= 68) {
                if (isPrintLog) printf("F1~F10(59~68): ");
                keyboardKey.keyBoardType = F1_F10;
            } else if (ch >= Fn_F1_F10 && ch <= 93) {
                if (isPrintLog) printf("[Shift + F1_F10(84~93)]: ");
                keyboardKey.keyBoardType = Fn_F1_F10;
            } else if (ch >=0 && ch < UnAscii) {
                if (isPrintLog) printf("[Shift + 小键盘(0~9.)]: (%c) ", ch);
                keyboardKey.keyBoardType = Ascii;
            } else {
                if (isPrintLog) printf("非ASCII字符: (%c) ", ch);
                keyboardKey.keyBoardType = UnAscii;
            }
            keyboardKey.isPressed = TRUE;
            keyboardKey.ch = ch;
            isStart0 = 0;
            return keyboardKey;
        } else if (isStart224) {
            if (ch == 72 || ch == 75 || ch == 77 || ch == 80) {
                if (isPrintLog) printf("箭头(↑72, ←75, →77, ↓80): ");
                keyboardKey.keyBoardType = Arrow;
            } else if (ch == Home) {
                if (isPrintLog) printf("Home(71): ");
                keyboardKey.keyBoardType = Home;
            } else if (ch == PageUp) {
                if (isPrintLog) printf("PageUp(73): ");
                keyboardKey.keyBoardType = PageUp;
            } else if (ch == End) {
                if (isPrintLog) printf("End(79): ");
                keyboardKey.keyBoardType = End;
            } else if (ch == PageDown) {
                if (isPrintLog) printf("PageDown(81): ");
                keyboardKey.keyBoardType = PageDown;
            } else if (ch == Delete) {
                if (isPrintLog) printf("Delete(83): ");
                keyboardKey.keyBoardType = Delete;
            } else if (ch == F11_F12 || ch == F11_F12 + 1) {
                if (isPrintLog) printf("F11,F12(133~134): ");
                keyboardKey.keyBoardType = F11_F12;
            } else if (ch == Fn_F11_F12 || ch == Fn_F11_F12 + 1) {
                if (isPrintLog) printf("[Shift + F11,F12(135~136)]: ");
                keyboardKey.keyBoardType = Fn_F11_F12;
            } else {
                if (isPrintLog) printf("非ASCII字符: (%c) ", ch);
                keyboardKey.keyBoardType = UnAscii;
            }
            keyboardKey.isPressed = TRUE;
            keyboardKey.ch = ch;
            isStart224 = 0;
            return keyboardKey;
        } else {
            /**
             * 2.再判断是否是组合输入 or '单键'
             */
            switch (ch) {
                case combination_key_0:
                    isStart0 = 1;
                    if (isPrintLog) printf("输入组合: (0) + ");
                    break;
                case combination_key_224:
                    isStart224 = 1;
                    if (isPrintLog) printf("输入组合: (224) + ");
                    break;
                default:
                    if (ch >= 0 && ch < UnAscii) {
                        if (isPrintLog) {
                            if (ch == 8) {  //backspace
                                printf("Ascii(BS (backspace)删除): ");
                            } else if (ch == 13) {  //enter
                                printf("Ascii(CR (carriage return)回车): ");
                            } else {
                                printf("Ascii(%c): ", ch);
                            }
                        }
                        keyboardKey.keyBoardType = Ascii;
                    } else {
                        if (isPrintLog) printf("非ASCII字符: (%c) ", ch);
                        keyboardKey.keyBoardType = UnAscii;
                    }
                    keyboardKey.isPressed = TRUE;
                    keyboardKey.ch = ch;
                    return keyboardKey;
            }
        }
    }
    keyboardKey.isPressed = FALSE;
    keyboardKey.keyBoardType = UnAscii;
    keyboardKey.ch = 0;
    return keyboardKey;
}
#endif //__CLION_CPPTEST_KEYBOARDUTILS_H__
